# -*- coding: utf-8 -*-
"""
-------------------------------------------------
# @Project  :pythonProject
# @File     :violator_special
# @Date     :2021/8/26 17:41
# @Author   :zhumenglong
# @Software :PyCharm
-------------------------------------------------
"""
import json

from wareHouse import *
from wareHouse import method

class Special:
    def __init__(self,file_path,Index_path,goal_path):
        self.file_path = file_path
        self.Index_path = Index_path
        self.goal_path = goal_path

    def get_keypoint(self):
        with open(self.Index_path, 'r', encoding='utf-8') as fp:
            while True:
                file_name = fp.readline()[:-1]
                # print(file_name)
                json_name = ""
                pict_name = ""
                if len(file_name) > 0 and len(file_name) > 15:
                    json_name = self.file_path + file_name + '_info.json'
                    pict_name = self.file_path + file_name + '.jpg'
                    Special.draw_pic_jpg(self,file_name, json_name, pict_name)
                    # print(json_name)
                    # print(pict_name)
                # elif len(file_name) > 0 and len(file_name) < 15:
                #     json_name = self.file_path + file_name + '_info.json'
                #     pict_name = self.file_path + file_name + '.jpeg'
                #     Special.draw_pic_jpg(self,file_name, json_name, pict_name)

                else:
                    break

    def draw_pic_jpg(self,file_name,json_name,pict_name):
        with open(json_name, 'r', encoding='utf-8') as f:
            # f.read()
            json_info = json.loads(f.read())
            img_info = method.cv2_imread(pict_name, -1)
            kk = 0
            for i in json_info:
                for num in json_info[i]:
                    for j in num:
                        if j == "box":
                            cat_name = str(kk)+"_person"
                            xmin = int(num[j]['x'])
                            ymin = int(num[j]['y'])
                            xmax = int(num[j]['x']) + int(num[j]['width'])
                            ymax = int(num[j]['y']) + int(num[j]['height'])
                            color = (250, 0, 0)
                            cv2.rectangle(img_info, (int(xmin), int(ymin)), (int(xmax), int(ymax)), color,
                                          2)
                            font = cv2.FONT_HERSHEY_SIMPLEX
                            cv2.putText(img_info, cat_name, (int(xmin), int(ymin)), font, 1, color, 2)

                        elif j == "key_point":

                            keypoint_thresh_vis = 0.3

                            keypoint = []
                            for ii in num[j]:
                                keypoint.append(ii)
                            keypoint = np.array(keypoint)

                            keypoint = keypoint.reshape((1, -1, 3))
                            joint_visible = keypoint[:, :, 2] > keypoint_thresh_vis
                            kpts_num = keypoint.shape[1]
                            for i1 in range(keypoint.shape[0]):
                                pts = keypoint[i1]
                                for color_i, jp in zip(colors, main_joint_pairs):
                                    if jp[0] >= kpts_num or jp[1] >= kpts_num: continue
                                    if joint_visible[i1, jp[0]] and joint_visible[i1, jp[1]]:
                                        pt0 = pts[jp, 0]
                                        pt1 = pts[jp, 1]
                                        pt0_0, pt0_1, pt1_0, pt1_1 = int(pt0[0]), int(pt0[1]), int(
                                            pt1[0]), int(pt1[1])

                                        cv2.line(img_info, (pt0_0, pt1_0), (pt0_1, pt1_1), color_i, 3)

                            l_r, std_distance, left_fall, right_fall = Special.special_detection(self,img_info, "",
                                                                                         keypoint, 1, 1, 0.3)

                            up_name = str(str(kk)+"_(" + str(l_r) + "," + str(std_distance) + "," + str(left_fall) + "," + str(
                                right_fall) + ")")
                            if std_distance > 0:
                                if left_fall > 0 or right_fall > 0:
                                    # print(pict_name)
                                    cv2.putText(img_info, str(up_name), (int(num['box']['x']), int(num['box']['y'] - 40)),
                                                cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 250, 0), 2)
                                else:
                                    cv2.putText(img_info, str(up_name), (int(num['box']['x']), int(num['box']['y'] - 40)),
                                                cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 250, 0), 2)
                            else:
                                cv2.putText(img_info, str(up_name), (int(num['box']['x']), int(num['box']['y'] - 40)),
                                            cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 250, 0), 2)
                        else:
                            if num['special'] == "false":
                                continue
                            else:
                                cv2.putText(img_info, str(kk)+"_"+num['special'], (600, 300), cv2.FONT_HERSHEY_SCRIPT_COMPLEX, 1,
                                            (0, 0, 250), 2)
                    kk+=1

            method.create_path(self.goal_path)

            if len(file_name) > 15:
                path1 = './' + self.goal_path + '/' + file_name + '.jpg'
                method.cv2_imwrite_jpg(path1, img_info)
            else:
                path1 = './' + self.goal_path + '/' + file_name + '.jpeg'
                # print(path1)
                method.cv2_imwrite_jpeg(path1, img_info)

    def get_sim(self,f1,f2):
        return np.dot(np.array(f1), np.array(f2).T)  #返回的是两个数组的点积，后边加.T表示行向量转化为列向量

    def special_detection(self,image, box, keypoint, keypoint_attr, person_occ, keypoint_thresh_vis=0.3):
        def pose_others(pts, nose2ankle, joint_visible):
            left_pts = nose2ankle[1]
            right_pts = nose2ankle[2]
            # if not(joint_visible[left_pts[0]] or joint_visible[right_pts[0]]): return -1, -2 #shoulder is not visible
            calc_idx = 1  # clac by left points
            # clac by right points
            vis_count_left = int(joint_visible[left_pts[0]]) + int(joint_visible[left_pts[1]]) + int(
                joint_visible[left_pts[2]])
            vis_count_right = int(joint_visible[right_pts[0]]) + int(joint_visible[right_pts[1]]) + int(
                joint_visible[right_pts[2]])
            # print(, joint_visible[right_pts[0]] + joint_visible[right_pts[1]] + joint_visible[right_pts[2]])
            if (vis_count_left < vis_count_right): calc_idx = 2

            if not joint_visible[nose2ankle[calc_idx][1]]: return calc_idx, -2  # shoulder on select side is must visible
            if not joint_visible[nose2ankle[calc_idx][1]]: return calc_idx, -3  # eblow on select side is must visible
            if not joint_visible[nose2ankle[calc_idx][2]]: return calc_idx, -4  # knee on select side is must visible

            # distance from shoulder to eblow
            jp = nose2ankle[calc_idx][:2]
            pt0 = pts[jp, 0]
            pt1 = pts[jp, 1]
            vec = np.array([pt0[1] - pt0[0], pt1[1] - pt1[0]])
            SE_dis = np.linalg.norm(vec)  # L2

            # distance from shoulder to knee
            jp = [nose2ankle[calc_idx][0], nose2ankle[calc_idx][2]]
            pt0 = pts[jp, 0]
            pt1 = pts[jp, 1]
            vec = np.array([pt0[1] - pt0[0], pt1[1] - pt1[0]])
            NA_dis = np.linalg.norm(vec)  # L2
            print(calc_idx, NA_dis, SE_dis)
            return calc_idx, NA_dis < SE_dis * 2.5

        def is_fall(pts, joint_pairs, joint_visible, attr):
            vec = [None] * 3
            for idx, jp in enumerate(joint_pairs):
                if jp[0] >= kpts_num or jp[1] >= kpts_num: continue
                if joint_visible[jp[0]] and joint_visible[jp[1]]:  # keypoints visible
                    pt0 = pts[jp, 0]
                    pt1 = pts[jp, 1]
                    vec[idx] = np.array([pt0[1] - pt0[0], pt1[1] - pt1[0]])
                    x_norm = np.linalg.norm(vec[idx])  # L2
                    vec[idx] = vec[idx] / x_norm
            leg_val, hip_val, body_val = False, False, False

            # lunyi
            if vec[1] is not None and vec[2] is not None:
                leg_val = Special.get_sim(self,vec[1], vec[2]) < math.cos(90. / 180. * math.pi)  # > 90

            # guaizhang
            if vec[0] is not None and vec[1] is not None:
                hip_val = Special.get_sim(self,vec[0], vec[1]) < math.cos(38. / 180. * math.pi)  # < 45
            if vec[0] is not None:
                body_val = Special.get_sim(self,np.array([0, 1]), vec[0]) < math.cos(38. / 180. * math.pi)

            # print(vec[0], vec[1], leg_val, thigh_val, shank_val)
            return leg_val * 1 + hip_val * 2 + body_val * 4

        # if person_occ < 0.5: return (-1, -1)
        left_side = [[5, 11], [11, 13], [13, 15]]  # top to down
        right_side = [[6, 12], [12, 14], [14, 16]]
        nose2ankle = [[0], [5, 7, 13], [6, 8, 14]]  # nose, left shoulder eblow knee, right shoulder eblow knee

        kpts_atrr = None  # keypoint_attr.reshape((1,-1,2))
        keypoint = keypoint.reshape((1, -1, 3))
        joint_visible = keypoint[:, :, 2] > keypoint_thresh_vis
        kpts_num = keypoint.shape[1]
        for i in range(keypoint.shape[0]):
            pts = keypoint[i]
            attr = None  # kpts_atrr[i]

            # remove bend
            l_r, std_distance = pose_others(pts, nose2ankle, joint_visible[i])
            left_fall = is_fall(pts, left_side, joint_visible[i], attr)
            right_fall = is_fall(pts, right_side, joint_visible[i], attr)
        return (l_r, std_distance, left_fall, right_fall)  # 如果std_distance大于0(或者为True)，且（left_fall, right_fall）有大于0的就报警
